<!DOCTYPE html>
<html>
  <head>
    <meta charset="UTF-8">
    <meta name="viewport" content="user-scalable=no, width=device-width, initial-scale=1.0, maximum-scale=1.0"/>
    <meta name="apple-mobile-web-app-capable" content="yes" />
    <meta name="apple-mobile-web-app-status-bar-style" content="black" />
    <title>Canvas Game Experiement - CodePen</title>
    <style>
      * {
          padding: 0;
          margin: 0;
      }

      html, body { width:100%; height:100%; } /* just to be sure these are full screen*/

      canvas { display:block; } /* To remove the scrollbars */

      #mycanvas {
        background: #eee;
        color: #222;
      }

    </style>
  </head>
  <body>
    <canvas id="mycanvas">Canvas doesn't work for you</canvas>
    <script>
    /*
      Games work by
      1. Start the loop
      2. Grab all control events
      3. Run the update function
      4. Erase background
      5. Redraw background
      6. Draw entities
    */


    // add a listener for all touch events
    document.addEventListener("touchstart", handleStart, false); 
    document.addEventListener("touchend", handleEnd, false);

    var requestAnimFrame = (function(){
    return window.requestAnimationFrame       ||
        window.webkitRequestAnimationFrame ||
        window.mozRequestAnimationFrame    ||
        window.oRequestAnimationFrame      ||
        window.msRequestAnimationFrame     ||
        function(callback){
            window.setTimeout(callback, 1000 / 60);
        };
    })(); 

    function cancelAnimationFrame(){
      var vendors = ['webkit', 'moz'];
      for(var x = 0; x < vendors.length && !window.requestAnimationFrame; ++x) {
      window.requestAnimationFrame = window[vendors[x]+'RequestAnimationFrame'];
      window.cancelAnimationFrame =
        window[vendors[x]+'CancelAnimationFrame'] || window[vendors[x]+'CancelRequestAnimationFrame'];
      }
    }

    var touchX = touchY = 0;

    var GameController = function() {
      this.canvas = document.getElementById("mycanvas");
      this.context = this.canvas.getContext("2d");
      this.canvas.height = Math.round(document.height); // height of the game
      this.canvas.width = Math.round(document.width); // width of the game     
      this.gameTitle = "Sausage Dog v1";
      this.bg = "white";
      this.lastAnimationFrameTime = 0;
      this.fps = 0;
      this.score = 10; // score counter
    }

    GameController.prototype.write_title = function() {
      gc.context.font = "20px Georgia";
      gc.context.fillText(this.gameTitle, 10, 25);
      gc.context.fillText(this.score, 40, 25);
    }

    GameController.prototype.draw_cell = function(x, y, dt) {
      gc.context.fillStyle = "blue";
      gc.context.fillRect(x*10, y*10, 10, 10);
    }

    GameController.prototype.draw = function(dt) {
      this.write_title();
      drawSnake(dt);
    }

    var Snake = function() {
      this.snake = []; // the actual snake itself
      this.cw = 10; // dimensions for snake body part
      this.d = "right"; // default direction the snake starts
      this.length = 10; // default length of the snake
      this.speed = 10; // default pixels per second to move the snake
    }
    Snake.prototype.build_snake = function(){
      for(var i = this.length-1; i>=0; i--)
      {
        //This will create a horizontal snake starting from the top left
        this.snake.push({x: i, y: 15});
      }
    };
    Snake.prototype.move_snake = function(key) {
      if(key == "37" && snake.d != "right") snake.d = "left";
      else if(key == "38" && snake.d != "down") snake.d = "up";
      else if(key == "39" && snake.d != "left") snake.d = "right";
      else if(key == "40" && snake.d != "up") snake.d = "down";
    }

    var Food = function() {
      this.x = Math.round(Math.random()*(w-snake.cw)/snake.cw);
      this.y = Math.round(Math.random()*(h-snake.cw)/snake.cw);
    }

    Food.prototype.set_corordinates = function() {
      this.x = Math.round(Math.random()*(w-snake.cw)/snake.cw);
      this.y = Math.round(Math.random()*(w-snake.cw)/snake.cw);
      console.log(this.x + " , " + this.y);
    }
    function handleStart(evt) {
      evt.preventDefault();
      touchX = evt.touches[0].screenX;
      touchY = evt.touches[0].screenY;
    }

    function handleEnd(evt) {
      evt.preventDefault();      

      if (touchX < (w/2) ) {
        if(snake.d != "down") {
          snake.d = "down";
        } else {
          snake.d = "left";
        }
      } else {
        if(snake.d != "up") {
          snake.d = "up";
        } else {
          snake.d = "right";
        }
      } 
    }

    var gc = new GameController();
    var h = gc.canvas.height;
    var w = gc.canvas.width;
    var snake = new Snake();
    var food = new Food();

    snake.build_snake();
   
    var lastTime;
    function loop() {
      var now = Date.now();    
      var dt = (now - lastTime) / 1000.0;    
      // update(dt); <- this should be the real call to update everything before drawing    
      // render(); <- this is the actual draw function
      gc.draw(dt);
      lastTime = now;    
      requestAnimFrame(loop);
    }

    loop();

    function drawSnake(dt) {

      //To avoid the snake trail we need to paint the BG on every frame
      //Lets paint the canvas now
      gc.context.fillStyle = gc.bg; 
      gc.context.fillRect(0, 0, w, h);
      
      //The movement code for the snake to come here.
      //The logic is simple
      //Pop out the tail cell and place it infront of the head cell
      var nx = snake.snake[0].x;
      var ny = snake.snake[0].y;

      //These were the position of the head cell.
      //We will increment it to get the new head position
      //Lets add proper direction based movement now
      if(snake.d == "right") nx++ *dt;
      else if(snake.d == "left") nx-- *dt;
      else if(snake.d == "up") ny-- *dt;
      else if(snake.d == "down") ny++ *dt;
      
      w = Math.round(w);
      h = Math.round(h);
      //Lets add the game over clauses now
      //This will restart the game if the snake hits the wall
      if(nx == -1 || nx == Math.round(w/snake.cw) || ny == -1 || ny == Math.round(h/snake.cw) || check_collision(nx, ny, snake.snake))
      {
        //restart game
        console.log(nx + " : " + ny + " | w/cw = " + Math.round(w/snake.cw));
        setTimeout(function(){
          cancelAnimationFrame();                
        }, 1)
        console.log('game over'); 
        //Lets organize the code a bit now.
        return;
      }
      
      //Lets write the code to make the snake eat the food
      //The logic is simple
      //If the new head position matches with that of the food,
      //Create a new head instead of moving the tail
      if(nx == food.x && ny == food.y) {
        var tail = {x: nx, y: ny};
        console.log("food eaten");
        food.set_corordinates();
      } else {
        var tail = snake.snake.pop(); //pops out the last cell
        tail.x = nx; tail.y = ny;
      }
      snake.snake.unshift(tail); //puts back the tail as the first cell     
          
      for(var i = 0; i < snake.snake.length; i++)
      {
        var c = snake.snake[i];
        //Lets paint 10px wide cells
        gc.draw_cell(c.x, c.y, dt);
      }
      //Lets paint the food
      console.log(food.x, food.y);
      gc.draw_cell(food.x, food.y);
    } 

    function check_collision(x, y, array)
    {
      //This function will check if the provided x/y coordinates exist
      //in an array of cells or not
      for(var i = 0; i < array.length; i++) {
        if(array[i].x == x && array[i].y == y) {
           return true;
        }
        return false;
      }
    }

    window.onkeydown = function(e) {
      snake.move_snake(e.keyCode);
    } 

  </script>
  </body>
</html>
